﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace collabr8
{
    // This class handles connections; there will be as many instances of it as there will be connected users
    public class Connection
    {
        TcpClient tcpClient;
        // The thread that will send information to the client
        private Thread thrSender;
        private BinaryFormatter formatter;
        private Message incoming, outgoing;
        private string currUser;
        private string currPassword;
        private Server server;
        private bool Connected;

        // The constructor of the class takes in a TCP connection
        public Connection(TcpClient tcpCon)
        {
            tcpClient = tcpCon;
            server = Server.Instance;
            this.formatter = new BinaryFormatter();
            // The thread that accepts the client and awaits messages
            thrSender = new Thread(AcceptClient);
            thrSender.IsBackground = true;
            // The thread calls the AcceptClient() method
            thrSender.Start();
        }

        public void CloseConnection()
        {
            // Close the currently open objects
            this.Connected = false;
            tcpClient.Close();
        }

        // Occures when a new client is accepted
        private void AcceptClient()
        {

            this.incoming = (Message)this.formatter.Deserialize(tcpClient.GetStream());
            this.currUser = this.incoming.Header;
            this.currPassword = this.incoming.Text;
            this.Connected = true;

            // We got a response from the client
            if (currUser != "")     // checking header for username
            {
                // Check usr+pwd, then store the user name in the hash table
                if (server.IsConnected(currUser))
                {
                    // Failed connection
                    this.outgoing = new Message(MessageCode.Connect, "  This username already exists.");
                    this.formatter.Serialize(tcpClient.GetStream(), this.outgoing);
                    CloseConnection();
                    return;
                }
                else if (currPassword != server.getPassword())
                {
                    // Failed connection
                    this.outgoing = new Message(MessageCode.Connect, "  Invalid Password.");
                    this.formatter.Serialize(tcpClient.GetStream(), this.outgoing);
                    CloseConnection();
                    return;
                }
                else
                {
                    // OK = connected successfully

                    this.outgoing = new Message(MessageCode.Connect, "OK");
                    this.formatter.Serialize(tcpClient.GetStream(), this.outgoing);

                    // Add the user to the hash tables and start listening for messages from him
                    server.AddUser(tcpClient, currUser);
                    server.AddConnection(this);
                }
            }
            else
            {
                CloseConnection();
                return;
            }

            try
            {
                // Keep waiting for a message from the user
                while (Connected)
                {
                    this.incoming = (Message)this.formatter.Deserialize(tcpClient.GetStream());
                    // TODO: Handle control messages

                    if (this.incoming.Code == MessageCode.Chat)
                        server.SendMessage(currUser, this.incoming.Text);
                }
            }
            catch
            {
                // If anything went wrong with this user, disconnect him
                server.RemoveUser(tcpClient);
                CloseConnection();
            }
        }
    } 
}
